// replace timeStep with delay

var map;
var geocoder;
var address;
var trafficInfo;
var toggleState = 1;
var addressMarker = null;
var animating = false;

var scheduledCheck;
var target; //slider

var polylines;
var polylineEncoder;

    %s

function help() { alert("This is a demo of our cloud application, which serves as a "
                        + "front-end for a system that models human "
                        + "behavior. Features are being added as you are reading "
                        + "this message.\n"
                        + "\n"
                        + "This demo allows you to visualize (over Google Maps) geo-located Twitter data and the interactions and friendship relationships among the users.\n"
                        + "\n"
                        + "You can interact with this app via the control panel and also using the following keys.\n\n"
                        + "Space bar:\t\t\t toggle play/pause\n"
                        + "Left and Right arrows:\t step backward/forward in time\n"
                        + "Up and Down arrows:\t speed the animation up/down\n"
                        + "Ctrl+s:\t\t\t\t stop animation\n");

                }

function createMarker(point, options, html) {
    var marker = new GMarker(point, options);
    // Create an array that will hold the tabs  
    var tabs = [];  
    // Create tabs and add them to the array  
    tabs.push(new GInfoWindowTab('Tweet', html));  
    tabs.push(new GInfoWindowTab('Other', 'TODO'));  

    GEvent.addListener(marker, "click",
	               function() {
                           marker.showMapBlowup({zoomLevel:18, mapType:G_HYBRID_MAP});
	               });

    // The new marker "mouseover" listener
    GEvent.addListener(marker,"mouseover", function() {
        marker.openInfoWindowTabsHtml(tabs); 
    });

    // The new marker "mouseout" listener
    GEvent.addListener(marker,"mouseout", function() {
	marker.closeInfoWindow();
    });

    return marker;
}

function updateMarker(player) {
    var marker = playerMarks[player];
    var html = '<font color="blue">' + points[player][pointers[player]][3] + '</font>'; 
    var tabs = [];  
    tabs.push(new GInfoWindowTab('Tweet', html));  
    tabs.push(new GInfoWindowTab('Other', 'TODO'));
    GEvent.clearListeners(marker, "mouseover");
    GEvent.clearListeners(marker, "click");
    GEvent.addListener(marker, "click", function() { marker.showMapBlowup({zoomLevel:18, mapType:G_HYBRID_MAP}); });
    GEvent.addListener(marker,"mouseover", function() {	marker.openInfoWindowTabsHtml(tabs); });
}

function getAddress(overlay, latlng) {
    if (latlng != null) {
	address = latlng;
        geocoder.getLocations(latlng, showAddress);
    }
}



function showAddress(response) {
    if (addressMarker != null) {
        map.removeOverlay(addressMarker);
    }
    if (!response || response.Status.code != 200) {
	alert("Status Code:" + response.Status.code);
    }
    else {
	place = response.Placemark[0];
        point = new GLatLng(place.Point.coordinates[1],place.Point.coordinates[0]);
        addressMarker = new GMarker(point, {draggable: true, bouncy: true} );
        map.addOverlay(addressMarker);

        var htmlToDisplay =  '<div class="bubble"'+
	    '<b>Click lat, lng: </b>' + response.name + '<br/>' +
            '<b>Address: </b><i>' + place.address + '</i><br>' +
            '<b>Projected lat, lng: </b>' + place.Point.coordinates[1] + ", " + place.Point.coordinates[0] + '<br>' +
	    '<b>Status Code: </b>' + response.Status.code + ' ' + '<b>Status Request: </b>' + response.Status.request +
            ' ' + '<b>Accuracy: </b>' + place.AddressDetails.Accuracy + ' ' +
            '<b>Country code: </b> ' + place.AddressDetails.Country.CountryNameCode+'</div>';

        GEvent.addListener(addressMarker, "dragstart", function() {
            map.closeInfoWindow();
        });

        GEvent.addListener(addressMarker, "dragend", function() {
            addressMarker.openInfoWindowHtml(htmlToDisplay);
        });

        addressMarker.openInfoWindowHtml(htmlToDisplay);



    }
}


function toggleTraffic() {
    if (toggleState == 1) {
        map.removeOverlay(trafficInfo);
        toggleState = 0;
    } else {
        map.addOverlay(trafficInfo);
        toggleState = 1;
    }
}


function getTrafficState() {
    if (toggleState) {
      	return "On";
    }
    else {
      	return "Off";
    }
}

function stepForward() {
    // current slider value
    var currentValue = parseInt(document.target.slider('option','value'));

    // current slider value increased
    var newValue = currentValue+realTimeAdd;

    // is new value greater than max value?
    if(newValue <= document.target.slider('option', 'max')) {
	// increase slider value
	document.target.slider('option', 'value', newValue);
	globalTime = newValue;
	displayPlayers(newValue);
	//map.setZoom(newValue);
    } else {
	// slider is at max value
	document.target.slider('option', 'value', document.target.slider('option', 'max'));
	globalTime = document.target.slider('option', 'max');
	displayPlayers(globalTime);
    }
    return false;
}

function stepBackward() {
    // current slider value
    var currentValue = parseInt(document.target.slider('option','value'));

    // current slider value increased 
    var newValue = currentValue-realTimeAdd;

    // is new value greater than max value?
    if(newValue >= document.target.slider('option', 'min')) {
	// increase slider value
	document.target.slider('option', 'value', newValue);
	globalTime = newValue;
	displayPlayers(newValue);
	//map.setZoom(newValue);
    }
    else{
	document.target.slider('option', 'value', document.target.slider('option', 'min'));
	globalTime = document.target.slider('option', 'min');
	displayPlayers(globalTime);
    }
    return false;
}

// main entry point
$(document).ready(function() {

    // bind keys to actions
    shortcut.add("right", stepForward);
    shortcut.add("left", stepBackward);
    shortcut.add("up", increaseSpeed);
    shortcut.add("down", decreaseSpeed);
    shortcut.add("space", playClick);
    shortcut.add("Ctrl+s", stopClick);

    document.getElementById('delayBox').value = delay;

    if (GBrowserIsCompatible()) {
	map = new GMap2(document.getElementById("map_canvas"));
        
        polylineEncoder = new PolylineEncoder(); 
        polylines = new Array(numPlayers);
        /*
          polylines2D = new Array(numPlayers);
          for (var x = 0; x<polylines2D.length; x++) {
          polylines2D[x]= new Array(numPlayers);
          }
        */

	var sw = new GLatLng(%s, %s);
	var ne = new GLatLng(%s, %s);

	var bounds = new GLatLngBounds(sw, ne);

        // set map to optimal zoom and center
	map.setCenter(new GLatLng(%s, %s), map.getBoundsZoomLevel(bounds)+2);

        map.setMapType(G_PHYSICAL_MAP);
        //map.setMapType(G_NORMAL_MAP);
        //map.setMapType(G_HYBRID_MAP);
        //map.setMapType(G_SATELLITE_MAP);

        // sets the map to "animate" zoom (only on double click and mouse wheel scroll)
	map.enableContinuousZoom();
	// enable the ability to zoom via mouse wheel
	map.enableScrollWheelZoom();


        map.addControl(new GLargeMapControl());
        map.addMapType(G_PHYSICAL_MAP);
        map.addMapType(G_SATELLITE_3D_MAP);

        // LOCAL SEARCH ENABLE
        //map.addControl(new google.maps.LocalSearch(), new  GControlPosition(G_ANCHOR_BOTTOM_RIGHT, new GSize(3,0)));
	//GSearch.setOnLoadCallback();

        map.addControl(new ExtMapTypeControl({showTraffic: true, showTrafficKey: true}));

        // ======================================================

        // show address on click
	//GEvent.addListener(map, "click", getAddress); geocoder = new
	//GClientGeocoder();

        /* 
        // show CTF flag positions
        var flagNorth = new GLatLng(43.12703, -77.62932);
        var flagSouth = new GLatLng(43.12475, -77.62980);

        var basic = new GIcon(G_DEFAULT_ICON);
        //basic.shadow = "http://chart.apis.google.com/chart?chst=d_map_pin_shadow";
        basic.shadow = null;
        basic.iconSize = new GSize(25, 25);
        basic.iconAnchor = new GPoint(12, 12);
        //basic.shadowSize = new GSize(34, 25);
        basic.infoWindowAnchor = new GPoint(9, 10);

        var i1 = new GIcon(basic);
        //i1.image = "http://chart.apis.google.com/chart?chst=d_map_pin_icon&chld=snow|FFFFFF";
        i1.image = "img/casetta_green.png";
        var i2 = new GIcon(basic);
        i2.image = "img/casetta_yellow.png";

        var markerNorth = new GMarker(flagNorth, {icon: i1, draggable: false, bouncy: false});
        var markerSouth = new GMarker(flagSouth, {icon: i2, draggable: false, bouncy: false});


        GEvent.addListener(markerNorth,"mouseover", function() {
	markerNorth.openInfoWindowHtml('<div class="bubble">North Flag</div>');
	});
    	GEvent.addListener(markerNorth,"mouseout", function() {
	markerNorth.closeInfoWindow();
	});

        GEvent.addListener(markerSouth,"mouseover", function() {
	markerSouth.openInfoWindowHtml('<div class="bubble">South Flag</div>');
	});
    	GEvent.addListener(markerSouth,"mouseout", function() {
	markerSouth.closeInfoWindow();
	});

        map.addOverlay(markerNorth);
        map.addOverlay(markerSouth);
        */

	// slider
	$(function() {
	    // slider document.target
	    document.target = $('#zoom-slider #zoom-path');

	    // create the slider
	    document.target.slider({
		orientation: 	'horizontal',
		value: 			minTime,
		min: 			minTime,
		max: 			maxTime,
		step: 			1,
		animate: 		false,
		stop: function() {
		    sliderBarClick(document.target.slider('option','value'));
		}
	    });

	    // update slider on zoom with double click
	    //GEvent.addListener(map, 'moveend', function() { document.target.slider('option','value', map.getZoom()); });

	    // maximum slider value
	    var maxValue = parseInt(document.target.slider('option', 'max'));

	    // minimum slider value
	    var minValue = parseInt(document.target.slider('option', 'min'));

	    // hook increase zoom control
	    $('#zoom-control-plus').click(stepForward);

	    // hook decrease zoom control
	    $('#zoom-control-minus').click(stepBackward);
	});


	prepareMarkers();
        var text = UNIXtoHuman(minTime);
        document.getElementById("timeBox").value = text;
        drawLines();
    }
});


function prepareMarkers() {

   	%s

}


function UNIXtoHuman(unix)
{
    var theDate = new Date(unix * 1000);
    
    //        dateString = theDate.toGMTString();
    //        dateString = theDate.toTimeString();
    dateString = theDate.toString();
    return dateString+" ("+unix+")";
}

function displayPlayers(t) {
    // read delay input field
    delay = parseInt(document.getElementById('delayBox').value);
    text = UNIXtoHuman(t);
    document.getElementById("timeBox").value = text;
    document.target.slider('option', 'value', t);
    
    // remove all old lines
    // 0 ... location hasn't changed from last udate
    // 1 ... location changed
    //var moved = new Array(numPlayers);

    // updatePointers
    for(var i=0; i<numPlayers; i++) {
        while (points[i][pointers[i]][2] > t && pointers[i] > 0) {
            pointers[i]--;
        }
    }

    // update markers
    // problematic: Mon May 24 2010 20:06:59 GMT-0400 (EDT) (1274746019)
    for(var i=0; i<numPlayers; i++) {
        if (pointers[i] >= points[i].length) {
            continue;
        }
        // display everything that happened between last update and t 
        while (points[i][pointers[i]][2] <= t) {
            if (pointers[i] == points[i].length-1) {
	        playerMarks[i].setLatLng(new google.maps.LatLng(points[i][pointers[i]][0], points[i][pointers[i]][1]));
                updateMarker(i);
                break;
            }
            //moved[i] = 1;
            updateMarker(i);
	    playerMarks[i].setLatLng(new google.maps.LatLng(points[i][pointers[i]][0], points[i][pointers[i]][1]));
            pointers[i]++;
        }
    }
    
    /*
    // draw new lines ALL the time
    for(i=0; i<numPlayers; i++) {
    for(var u=0; u<friends[i].length; u++){
    var friend = friends[i][u];
    if ((moved[i]==0 && moved[friend]==0) || friend<=i){
    continue;
    }
    if (polylines[i][friend] != null) {
    map.removeOverlay(polylines[i][friend]);
    polylines[i][friend];
    }
    var point1 = new google.maps.LatLng(points[i][pointers[i]][0], points[i][pointers[i]][1]);
    var point2 = new google.maps.LatLng(points[friend][pointers[friend]][0], points[friend][pointers[friend]][1]);
    var line = new Array(2);
    line = [ point1, point2 ];
    // encoded polylines (more overhead, but then faster)
    polylines2D[i][friend] = polylineEncoder.dpEncodeToGPolyline(line, '#FF0000', 1, 0.6)
    // unencoded
    //polylines2D[i][friend] = new GPolyline(line, '#FF0000', 1, 0.6);
    map.addOverlay(polylines2D[i][friend]);  
    }
    }
    */
}


function sliderBarClick(t) {
    globalTime = t;

    if (paused == false) {
        if (scheduledCheck != null) {
	    clearTimeout(scheduledCheck);
	}
	document.getElementById('pauseButton').src="themes/default/images/pause_b.png";
      	document.getElementById('playButton').src="themes/default/images/play.png";
     	document.getElementById('stopButton').src="themes/default/images/stop.png";
     	paused = true;
    }
    displayPlayers(t);
}


function changeAnimation(newTime) {
    //cancel outstanding scheduled event
    if (scheduledCheck != null) {
	clearTimeout(scheduledCheck);
    }
    globalTime = newTime;
    animatePlayers();
}

function increaseSpeed() {
    currTime = parseInt(document.getElementById('delayBox').value);
    newTime = currTime - 10;
    if (newTime >= 0) {
	delay = newTime;
	document.getElementById('delayBox').value = newTime;
    }
}

function decreaseSpeed() {
    currTime = parseInt(document.getElementById('delayBox').value);
    newTime = currTime + 10;
    delay = newTime;
    document.getElementById('delayBox').value = newTime;
}


function animatePlayers() {
    displayPlayers(globalTime);
    if (globalTime > maxTime || globalTime<minTime) {
    	return;
    }
    globalTime += realTimeAdd;
    //schedule another time step
    scheduledCheck = setTimeout("animatePlayers()",delay);
}



function play() {
    clearLines();
    changeAnimation(globalTime);
    document.getElementById('pauseButton').src="themes/default/images/pause.png";
    document.getElementById('playButton').src="themes/default/images/play_b.png";
    document.getElementById('stopButton').src="themes/default/images/stop.png";
    paused = false;
    stopped = false;
}

function pause() {
    if (scheduledCheck != null) {
	clearTimeout(scheduledCheck);
    }
    drawLines();
    document.getElementById('pauseButton').src="themes/default/images/pause_b.png";
    document.getElementById('playButton').src="themes/default/images/play.png";
    document.getElementById('stopButton').src="themes/default/images/stop.png";
    paused = true;

}

function playClick() {
    if (paused == false && stopped==false) {
      	pause();
        return;
    }
    play();
}


function drawLines() {
    for(var i=0; i<numPlayers; i++) {
        // now the pointer[i] points to the next time step, need to go back if not at the extremes
        var p;
        if (pointers[i] > 0 && pointers[i] < points[i].length-1) {
            p = pointers[i] - 1;
        }
        else { p = pointers[i]; }

        for(var u=0; u<friends[i].length; u++){
            var friend = friends[i][u];
            // avoid drawing each line twice
            if (friend<=i){
                continue;
            }
            var f;
            if (pointers[friend] > 0 && pointers[friend] < points[friend].length-1) {
                f = pointers[friend] -1 ;
            }
            else { f = pointers[friend]; }
            var point1 = new google.maps.LatLng(points[i][p][0], points[i][p][1]);
            var point2 = new google.maps.LatLng(points[friend][f][0], points[friend][f][1]);
            var line = new Array(2);
            line = [ point1, point2 ];
            // encoded polylines (more overhead, but then faster)
            var polyline = polylineEncoder.dpEncodeToGPolyline(line, '#FF0000', 1, 0.6);
            // unencoded
            //var polyline = new GPolyline(line, '#FF0000', 1, 0.6);
            polylines.push(polyline);
            map.addOverlay(polyline);
        }
    }
}

function clearLines() {
    var i;
    for (i=0; i<polylines.length; i++) {
        if (polylines[i] != null) {
            map.removeOverlay(polylines[i]);
        }
    }
    polylines = new Array(numPlayers);
}

function pauseClick() {
    if (stopped==true){ 
        drawLines();
        return; 
    }
    if (paused == false) {
        pause();
    }
    else { // paused => unpause
        play();
    }
}

function stopClick() {
    if (scheduledCheck != null) {
	clearTimeout(scheduledCheck);
    }
    globalTime = minTime;
    document.getElementById("timeBox").value = UNIXtoHuman(minTime);
    document.target.slider('option', 'value', minTime );
    document.getElementById('stopButton').src="themes/default/images/stop_b.png";
    document.getElementById('playButton').src="themes/default/images/play.png";
    document.getElementById('pauseButton').src="themes/default/images/pause.png";
    paused = false;
    stopped = true;
}



